home *** CD-ROM | disk | FTP | other *** search
/ Freelog 125 / Freelog_MarsAvril2015_No125.iso / Musique / Quod Libet / quodlibet-3.3.0-installer.exe / bin / quodlibet / parse / _diacritic.pyc (.txt) < prev    next >
Python Compiled Bytecode  |  2014-12-31  |  9KB  |  311 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.7)
  3.  
  4. '''
  5. Ways to let ASCII characters match other unicode characters which
  6. can be decomposed into one ASCII character and one or more combining
  7. diacritic marks. This allows to match e.g. "M\xc3\xbam" using "Mum".
  8.  
  9. re_add_diacritic_variants(u"Mum") =>
  10.     u"[M\xe1\xb8\xbe\xe1\xb9\x80\xe1\xb9\x82][u\xc3\xb9\xc3\xba\xc3\xbb\xc3\xbc\xc5\xa9\xc5\xab\xc5\xad\xc5\xaf\xc5\xb1\xc5\xb3\xc6\xb0\xc7\x94\xc7\x96\xc7\x98\xc7\x9a\xc7\x9c\xc8\x95\xc8\x97\xe1\xb9\xb3\xe1\xb9\xb5\xe1\xb9\xb7\xe1\xb9\xb9\xe1\xb9\xbb\xe1\xbb\xa5\xe1\xbb\xa7\xe1\xbb\xa9\xe1\xbb\xab\xe1\xbb\xad\xe1\xbb\xaf\xe1\xbb\xb1][m\xe1\xb8\xbf\xe1\xb9\x81\xe1\xb9\x83]"
  11. '''
  12. import sre_parse
  13. import unicodedata
  14. import sys
  15. from quodlibet.util import re_escape
  16. _DIACRITIC_CACHE = {
  17.     u'\xcc\x80': u'AEINOUWYaeinouwy\xce\x91\xce\x95\xce\x97\xce\x99\xce\x9f\xce\xa5\xce\xa9\xce\xb1\xce\xb5\xce\xb7\xce\xb9\xce\xbf\xcf\x85\xcf\x89\xd0\x95\xd0\x98\xd0\xb5\xd0\xb8',
  18.     u'\xcc\x80\xcd\x85': u'\xce\xb1\xce\xb7\xcf\x89',
  19.     u'\xcc\x81': u'ACEGIKLMNOPRSUWYZacegiklmnoprsuwyz\xc3\x86\xc3\x98\xc3\xa6\xc3\xb8\xce\x91\xce\x95\xce\x97\xce\x99\xce\x9f\xce\xa5\xce\xa9\xce\xb1\xce\xb5\xce\xb7\xce\xb9\xce\xbf\xcf\x85\xcf\x89\xd0\x93\xd0\x9a\xd0\xb3\xd0\xba',
  20.     u'\xcc\x81\xcc\x87': u'Ss',
  21.     u'\xcc\x81\xcd\x85': u'\xce\xb1\xce\xb7\xcf\x89',
  22.     u'\xcc\x82': u'ACEGHIJOSUWYZaceghijosuwyz',
  23.     u'\xcc\x82\xcc\x80': u'AEOaeo',
  24.     u'\xcc\x82\xcc\x81': u'AEOaeo',
  25.     u'\xcc\x82\xcc\x83': u'AEOaeo',
  26.     u'\xcc\x82\xcc\x89': u'AEOaeo',
  27.     u'\xcc\x83': u'AEINOUVYaeinouvy',
  28.     u'\xcc\x83\xcc\x81': u'OUou',
  29.     u'\xcc\x83\xcc\x84': u'Oo',
  30.     u'\xcc\x83\xcc\x88': u'Oo',
  31.     u'\xcc\x84': u'AEGIOUYaegiouy\xc3\x86\xc3\xa6\xce\x91\xce\x99\xce\xa5\xce\xb1\xce\xb9\xcf\x85\xd0\x98\xd0\xa3\xd0\xb8\xd1\x83',
  32.     u'\xcc\x84\xcc\x80': u'EOeo',
  33.     u'\xcc\x84\xcc\x81': u'EOeo',
  34.     u'\xcc\x84\xcc\x88': u'Uu',
  35.     u'\xcc\x86': u'AEGIOUaegiou\xce\x91\xce\x99\xce\xa5\xce\xb1\xce\xb9\xcf\x85\xd0\x90\xd0\x95\xd0\x96\xd0\x98\xd0\xa3\xd0\xb0\xd0\xb5\xd0\xb6\xd0\xb8\xd1\x83',
  36.     u'\xcc\x86\xcc\x80': u'Aa',
  37.     u'\xcc\x86\xcc\x81': u'Aa',
  38.     u'\xcc\x86\xcc\x83': u'Aa',
  39.     u'\xcc\x86\xcc\x89': u'Aa',
  40.     u'\xcc\x87': u'ABCDEFGHIMNOPRSTWXYZabcdefghmnoprstwxyz',
  41.     u'\xcc\x87\xcc\x84': u'AOao',
  42.     u'\xcc\x88': u'AEHIOUWXYaehiotuwxy\xce\x99\xce\xa5\xce\xb9\xcf\x85\xd0\x86\xd0\x90\xd0\x95\xd0\x96\xd0\x97\xd0\x98\xd0\x9e\xd0\xa3\xd0\xa7\xd0\xab\xd0\xad\xd0\xb0\xd0\xb5\xd0\xb6\xd0\xb7\xd0\xb8\xd0\xbe\xd1\x83\xd1\x87\xd1\x8b\xd1\x8d\xd1\x96\xd3\x98\xd3\x99\xd3\xa8\xd3\xa9',
  43.     u'\xcc\x88\xcc\x80': u'Uu\xce\xb9\xcf\x85',
  44.     u'\xcc\x88\xcc\x81': u'IUiu\xce\xb9\xcf\x85',
  45.     u'\xcc\x88\xcc\x84': u'AOUaou',
  46.     u'\xcc\x88\xcc\x8c': u'Uu',
  47.     u'\xcc\x88\xcd\x82': u'\xce\xb9\xcf\x85',
  48.     u'\xcc\x89': u'AEIOUYaeiouy',
  49.     u'\xcc\x8a': u'AUauwy',
  50.     u'\xcc\x8a\xcc\x81': u'Aa',
  51.     u'\xcc\x8b': u'OUou\xd0\xa3\xd1\x83',
  52.     u'\xcc\x8c': u'ACDEGHIKLNORSTUZacdeghijklnorstuz\xc6\xb7\xca\x92',
  53.     u'\xcc\x8c\xcc\x87': u'Ss',
  54.     u'\xcc\x8f': u'AEIORUaeioru\xd1\xb4\xd1\xb5',
  55.     u'\xcc\x91': u'AEIORUaeioru',
  56.     u'\xcc\x93': u'\xce\x91\xce\x95\xce\x97\xce\x99\xce\x9f\xce\xa9\xce\xb1\xce\xb5\xce\xb7\xce\xb9\xce\xbf\xcf\x81\xcf\x85\xcf\x89',
  57.     u'\xcc\x93\xcc\x80': u'\xce\x91\xce\x95\xce\x97\xce\x99\xce\x9f\xce\xa9\xce\xb1\xce\xb5\xce\xb7\xce\xb9\xce\xbf\xcf\x85\xcf\x89',
  58.     u'\xcc\x93\xcc\x80\xcd\x85': u'\xce\x91\xce\x97\xce\xa9\xce\xb1\xce\xb7\xcf\x89',
  59.     u'\xcc\x93\xcc\x81': u'\xce\x91\xce\x95\xce\x97\xce\x99\xce\x9f\xce\xa9\xce\xb1\xce\xb5\xce\xb7\xce\xb9\xce\xbf\xcf\x85\xcf\x89',
  60.     u'\xcc\x93\xcc\x81\xcd\x85': u'\xce\x91\xce\x97\xce\xa9\xce\xb1\xce\xb7\xcf\x89',
  61.     u'\xcc\x93\xcd\x82': u'\xce\x91\xce\x97\xce\x99\xce\xa9\xce\xb1\xce\xb7\xce\xb9\xcf\x85\xcf\x89',
  62.     u'\xcc\x93\xcd\x82\xcd\x85': u'\xce\x91\xce\x97\xce\xa9\xce\xb1\xce\xb7\xcf\x89',
  63.     u'\xcc\x93\xcd\x85': u'\xce\x91\xce\x97\xce\xa9\xce\xb1\xce\xb7\xcf\x89',
  64.     u'\xcc\x94': u'\xce\x91\xce\x95\xce\x97\xce\x99\xce\x9f\xce\xa1\xce\xa5\xce\xa9\xce\xb1\xce\xb5\xce\xb7\xce\xb9\xce\xbf\xcf\x81\xcf\x85\xcf\x89',
  65.     u'\xcc\x94\xcc\x80': u'\xce\x91\xce\x95\xce\x97\xce\x99\xce\x9f\xce\xa5\xce\xa9\xce\xb1\xce\xb5\xce\xb7\xce\xb9\xce\xbf\xcf\x85\xcf\x89',
  66.     u'\xcc\x94\xcc\x80\xcd\x85': u'\xce\x91\xce\x97\xce\xa9\xce\xb1\xce\xb7\xcf\x89',
  67.     u'\xcc\x94\xcc\x81': u'\xce\x91\xce\x95\xce\x97\xce\x99\xce\x9f\xce\xa5\xce\xa9\xce\xb1\xce\xb5\xce\xb7\xce\xb9\xce\xbf\xcf\x85\xcf\x89',
  68.     u'\xcc\x94\xcc\x81\xcd\x85': u'\xce\x91\xce\x97\xce\xa9\xce\xb1\xce\xb7\xcf\x89',
  69.     u'\xcc\x94\xcd\x82': u'\xce\x91\xce\x97\xce\x99\xce\xa5\xce\xa9\xce\xb1\xce\xb7\xce\xb9\xcf\x85\xcf\x89',
  70.     u'\xcc\x94\xcd\x82\xcd\x85': u'\xce\x91\xce\x97\xce\xa9\xce\xb1\xce\xb7\xcf\x89',
  71.     u'\xcc\x94\xcd\x85': u'\xce\x91\xce\x97\xce\xa9\xce\xb1\xce\xb7\xcf\x89',
  72.     u'\xcc\x9b': u'OUou',
  73.     u'\xcc\x9b\xcc\x80': u'OUou',
  74.     u'\xcc\x9b\xcc\x81': u'OUou',
  75.     u'\xcc\x9b\xcc\x83': u'OUou',
  76.     u'\xcc\x9b\xcc\x89': u'OUou',
  77.     u'\xcc\x9b\xcc\xa3': u'OUou',
  78.     u'\xcc\xa3': u'ABDEHIKLMNORSTUVWYZabdehiklmnorstuvwyz',
  79.     u'\xcc\xa3\xcc\x82': u'AEOaeo',
  80.     u'\xcc\xa3\xcc\x84': u'LRlr',
  81.     u'\xcc\xa3\xcc\x86': u'Aa',
  82.     u'\xcc\xa3\xcc\x87': u'Ss',
  83.     u'\xcc\xa4': u'Uu',
  84.     u'\xcc\xa5': u'Aa',
  85.     u'\xcc\xa6': u'STst',
  86.     u'\xcc\xa7': u'CDEGHKLNRSTcdeghklnrst',
  87.     u'\xcc\xa7\xcc\x81': u'Cc',
  88.     u'\xcc\xa7\xcc\x86': u'Ee',
  89.     u'\xcc\xa8': u'AEIOUaeiou',
  90.     u'\xcc\xa8\xcc\x84': u'Oo',
  91.     u'\xcc\xad': u'DELNTUdelntu',
  92.     u'\xcc\xae': u'Hh',
  93.     u'\xcc\xb0': u'EIUeiu',
  94.     u'\xcc\xb1': u'BDKLNRTZbdhklnrtz',
  95.     u'\xcd\x82': u'\xce\xb1\xce\xb7\xce\xb9\xcf\x85\xcf\x89',
  96.     u'\xcd\x82\xcd\x85': u'\xce\xb1\xce\xb7\xcf\x89',
  97.     u'\xcd\x85': u'\xce\x91\xce\x97\xce\xa9\xce\xb1\xce\xb7\xcf\x89' }
  98.  
  99. def diacritic_for_letters(regenerate = False):
  100.     '''Returns a mapping for combining diacritic mark to ascii characters
  101.     for which they can be used to combine to a single unicode char.
  102.  
  103.     (actually not ascii, but unicode from the Lu/Ll/Lt categories,
  104.     but mainly ascii)
  105.  
  106.     Since this is quite expensive to compute, the result is a cached version
  107.     unless regenerate != True. regenerate = True is used for unittests
  108.     to validate the cache.
  109.     '''
  110.     if not regenerate:
  111.         return _DIACRITIC_CACHE
  112.     d = None
  113.     for i in xrange(sys.maxunicode):
  114.         u = unichr(i)
  115.         n = unicodedata.normalize('NFKD', u)
  116.         if len(n) <= 1:
  117.             continue
  118.         if unicodedata.category(u) not in ('Lu', 'Ll', 'Lt'):
  119.             continue
  120.         if not all(map(unicodedata.combining, n[1:])):
  121.             continue
  122.         d.setdefault(n[1:], set()).add(n[0])
  123.     
  124.     for k, v in d.items():
  125.         d[k] = u''.join(sorted(v))
  126.     
  127.     return d
  128.  
  129.  
  130. def generate_re_diacritic_mapping(_diacritic_for_letters):
  131.     letter_to_variants = { }
  132.     for dia, letters in _diacritic_for_letters.iteritems():
  133.         for c in letters:
  134.             unichar = unicodedata.normalize('NFKC', c + dia)
  135.             letter_to_variants.setdefault(c, []).append(unichar)
  136.         
  137.     
  138.     for k, v in letter_to_variants.items():
  139.         letter_to_variants[k] = u''.join(sorted(v))
  140.     
  141.     return letter_to_variants
  142.  
  143.  
  144. def _fixup_literal(literal, in_seq, mapping):
  145.     u = unichr(literal)
  146.     if u in mapping:
  147.         u = u + mapping[u]
  148.     need_seq = len(u) > 1
  149.     u = re_escape(u)
  150.     if need_seq and not in_seq:
  151.         u = u'[%s]' % u
  152.     return u
  153.  
  154.  
  155. def _fixup_not_literal(literal, mapping):
  156.     u = unichr(literal)
  157.     if u in mapping:
  158.         u = u + mapping[u]
  159.     u = re_escape(u)
  160.     return u'[^%s]' % u
  161.  
  162.  
  163. def _fixup_range(start, end, mapping):
  164.     extra = []
  165.     for i in xrange(start, end + 1):
  166.         u = unichr(i)
  167.         if u in mapping:
  168.             extra.append(re_escape(mapping[u]))
  169.             continue
  170.     start = re_escape(unichr(start))
  171.     end = re_escape(unichr(end))
  172.     return u'%s%s-%s' % (''.join(extra), start, end)
  173.  
  174.  
  175. def _construct_regexp(pattern, mapping):
  176.     '''Raises NotImplementedError'''
  177.     parts = []
  178.     for op, av in pattern:
  179.         if op == 'not_literal':
  180.             parts.append(_fixup_not_literal(av, mapping))
  181.             continue
  182.         if op == 'literal':
  183.             parts.append(_fixup_literal(av, False, mapping))
  184.             continue
  185.         if op == 'category':
  186.             cats = {
  187.                 'category_word': u'\\w',
  188.                 'category_not_word': u'\\W',
  189.                 'category_digit': u'\\d',
  190.                 'category_not_digit': u'\\D',
  191.                 'category_space': u'\\s',
  192.                 'category_not_space': u'\\S' }
  193.             
  194.             try:
  195.                 parts.append(cats[av])
  196.             except KeyError:
  197.                 raise NotImplementedError(av)
  198.             
  199.  
  200.         if op == 'any':
  201.             parts.append(u'.')
  202.             continue
  203.         if op == 'negate':
  204.             parts.append(u'^')
  205.             continue
  206.         if op == 'in':
  207.             in_parts = []
  208.             for entry in av:
  209.                 (op, eav) = entry
  210.                 if op == 'literal':
  211.                     in_parts.append(_fixup_literal(eav, True, mapping))
  212.                     continue
  213.                 in_parts.append(_construct_regexp([
  214.                     entry], mapping))
  215.             
  216.             parts.append(u'[%s]' % u''.join(in_parts))
  217.             continue
  218.         if op == 'range':
  219.             (start, end) = av
  220.             parts.append(_fixup_range(start, end, mapping))
  221.             continue
  222.         if op == 'max_repeat' or op == 'min_repeat':
  223.             (min_, max_, pad) = av
  224.             pad = _construct_regexp(pad, mapping)
  225.             if min_ == 1 and max_ == sre_parse.MAXREPEAT:
  226.                 parts.append(u'%s+' % pad)
  227.             elif min_ == 0 and max_ == sre_parse.MAXREPEAT:
  228.                 parts.append(u'%s*' % pad)
  229.             elif min_ == 0 and max_ == 1:
  230.                 parts.append(u'%s?' % pad)
  231.             else:
  232.                 parts.append(u'%s{%d,%d}' % (pad, min_, max_))
  233.             if op == 'min_repeat':
  234.                 parts[-1] = parts[-1] + u'?'
  235.             
  236.         if op == 'at':
  237.             ats = {
  238.                 'at_beginning': u'^',
  239.                 'at_end': u'$',
  240.                 'at_beginning_string': u'\\A',
  241.                 'at_boundary': u'\\b',
  242.                 'at_non_boundary': u'\\B',
  243.                 'at_end_string': u'\\Z' }
  244.             
  245.             try:
  246.                 parts.append(ats[av])
  247.             except KeyError:
  248.                 raise NotImplementedError(av)
  249.             
  250.  
  251.         if op == 'subpattern':
  252.             (group, pad) = av
  253.             pad = _construct_regexp(pad, mapping)
  254.             if group is None:
  255.                 parts.append(u'(?:%s)' % pad)
  256.             else:
  257.                 parts.append(u'(%s)' % pad)
  258.         if op == 'assert':
  259.             (direction, pad) = av
  260.             pad = _construct_regexp(pad, mapping)
  261.             if direction == 1:
  262.                 parts.append(u'(?=%s)' % pad)
  263.             elif direction == -1:
  264.                 parts.append(u'(?<=%s)' % pad)
  265.             else:
  266.                 raise NotImplementedError(direction)
  267.         if op == 'assert_not':
  268.             (direction, pad) = av
  269.             pad = _construct_regexp(pad, mapping)
  270.             if direction == 1:
  271.                 parts.append(u'(?!%s)' % pad)
  272.             elif direction == -1:
  273.                 parts.append(u'(?<!%s)' % pad)
  274.             else:
  275.                 raise NotImplementedError(direction)
  276.         if op == 'branch':
  277.             (dummy, branches) = av
  278.             branches = (map,)((lambda b: _construct_regexp(b, mapping)), branches)
  279.             parts.append(u'%s' % u'|'.join(branches))
  280.             continue
  281.         raise NotImplementedError(op)
  282.     
  283.     return u''.join(parts)
  284.  
  285.  
  286. def re_replace_literals(text, mapping):
  287.     '''Raises NotImplementedError or re.error'''
  288.     if not isinstance(text, unicode):
  289.         raise AssertionError
  290.     pattern = None.parse(text)
  291.     return _construct_regexp(pattern, mapping)
  292.  
  293. _diacritic_mapping = generate_re_diacritic_mapping(diacritic_for_letters(regenerate = False))
  294.  
  295. def re_add_diacritic_variants(text):
  296.     '''Will replace all occurrences of ascii chars
  297.     by a bracket expression containing the character and all its
  298.     variants with a diacritic mark.
  299.  
  300.     "f\xc3\xb6hn" -> "[f\xe1\xb8\x9f]\xc3\xb6[h\xc4\xa5\xc8\x9f\xe1\xb8\xa3\xe1\xb8\xa5\xe1\xb8\xa7\xe1\xb8\xa9\xe1\xb8\xab\xe1\xba\x96][n\xc3\xb1\xc5\x84\xc5\x86\xc5\x88\xc7\xb9\xe1\xb9\x85\xe1\xb9\x87\xe1\xb9\x89\xe1\xb9\x8b]"
  301.  
  302.     In case the passed in regex is invalid raises re.error.
  303.  
  304.     Supports all regexp except ones with group references. In
  305.     case something is not supported NotImplementedError gets raised.
  306.     '''
  307.     if not isinstance(text, unicode):
  308.         raise AssertionError
  309.     return None(text, _diacritic_mapping)
  310.  
  311.